package com.hxrk.cecardvr;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;

import com.hxrk.jni.Mp4v2Native;
import com.mediatek.carcorder.CameraDevice;
import com.mediatek.carcorder.CarcorderManager;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import java.io.File;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import static com.hxrk.cecardvr.CamService.IsWatermarkexDate;

/**
 * Created by Administrator on 2016/11/15.
 */
public class CamParameter {
    private static final String TAG = "CamParameter";

    public static final int FMT_TYPE_YUV420 = 0;
    public static final int FMT_TYPE_YUV422 = 1;
    public static final int FMT_TYPE_MJPEG = 8;
    public static final int FMT_TYPE_H264 = 28;

    public static final int DEV_TYPE_USB = 1;
    public static final int DEV_TYPE_MIPI = 2;

    public int CamID = 0;
    //宽高
    public int IMG_WIDTH = 0;
    public int IMG_HEIGHT = 0;
    public int IMG_SUB_WIDTH = 640;
    public int IMG_SUB_HEIGHT = 480;
    public int IMG_TYPE = 0;
    public int DEV_TYPE = 0;
    public byte[] IMG_DATA = null;
    public byte[] IMG_DATA_COPY = null;
    private byte[] IMG_SUB_DATA = null;
    public byte[] IMG_DATA_264 = null;
    private int IMG_LENGTH = 0;
    public byte[] IMG_NV21 = null;
    //Video
    private int IMG_TIMESCALE = 0;
    private int IMG_FPS = 0;
    private int FPS = 15;
    public int IMG_FPS_TIME = 0;
    //Audio
    private int IMG_A_TIMESCALE = 0;
    private int IMG_A_SAMPLE = 0;

    private boolean usbDataisUploading = false;

    //数据线程同步
    public Object datasyn = new Object();

    //图像文件线程同步
    public Object videosyn = new Object();

    // 录制保存开始时间
    public long saveStart = 0;
    // 录制5分钟一个包
    public long savetik = 1000 * 60 * 5;

    // 是否正在录制
    public boolean savefile = false;

    // 最后一次 videoread 时间
    public static long endVideoreadTime = 0;

    // 当前录制保存的文件名
    public String savefilename = "";

    public int frameTik = 0;
    public int frameCount = 0;

    //是否报警
    public boolean isAlarmVideo = false;
    public boolean isAlarmAudio = false;
    public boolean isAlarmPicture = false;

    //    // ffmpeg
//    public FFmpegFrameRecorder recorder;
    //音视频线程同步
    public Object audiosyn = new Object();

    //水印字体
    public Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public long MP4FileHandle = 0;

    //rtp服务器IP
    public String rtp_IP = "";
    //rtp服务器端口
    public int rtp_Port = 0;
    //rtpUDP服务器端口
    public int rtp_UdpPort = 0;
    //监控数据类型
    public int rtp_DataType = 0;
    //快进快退标识
    public int rtp_KJKT = 0;
    //码流类型
    public int rtp_StreamType = 0;

    /*MIPI Camera bin*/
    public Camera mCamera;
    private int cameraPosition = 1;//1代表前置摄像头，0代表后置摄像头
    private MediaRecorder mRecorder;
    /*MIPI Camera end*/

    public Bitmap bmp = null;
    public Bitmap bmpFace = null;
    public Object bmpsyn = new Object();
    public Object facesyn = new Object();

    //RGB数据指针
    public long rgbdatap = 0;

    //BGR数据指针
    public long bgrdatap = 0;

    public byte[] m_info = null;
    public MediaCodec mediaVideoCodec = null;

    public byte[] m_sub_info = null;
    public MediaCodec sub_mediaVideoCodec = null;

    private byte[] mSpsData = null;

    public Bundle CMDBundle = new Bundle();

    public CamParameter(int camid) {
        CamID = camid;
    }

    public void release() {
        Mp4v2Native.getInstance().jpegclose(CamID);
//            MyApplication.yuvToRgbNative.nativeYuvRelease(CamID);
    }

    public boolean[] cameraFrameReady = new boolean[2];
    public Mat[] mFrameChain;
    public JavaCameraFrame[] mCameraFrame;
    public Mat[] mFaceMat;

    public static boolean serviceFlag;
    public static CameraDevice mMainCameraDevice;
    private static CarcorderManager mCarcorderManager;

    private long StartTime = 0;
    public  boolean sendMipiData = false;
    public boolean deviceState = false;
    public void initBmp(int width, int height, int fmtType, int timeScale, int fps, int a_timeScale, int a_sample, int devType) {
        try {
            synchronized (datasyn) {

                IMG_WIDTH = width;
                IMG_HEIGHT = height;
                IMG_TYPE = fmtType;
                deviceState = true;

                if (devType == DEV_TYPE_MIPI) {
                    if (initCameara() == -1) {
                        return;
                    }
                }

                DEV_TYPE = devType;
                IMG_FPS = fps;
                IMG_FPS_TIME = 1000 / fps;
                IMG_TIMESCALE = timeScale;
                IMG_A_TIMESCALE = a_timeScale;
                IMG_A_SAMPLE = a_sample;

                bmp = Bitmap.createBitmap(IMG_WIDTH, IMG_HEIGHT, Bitmap.Config.ARGB_8888);
                bmpFace = Bitmap.createBitmap(IMG_WIDTH, IMG_HEIGHT, Bitmap.Config.ARGB_8888);

                mFrameChain = new Mat[2];
                mFrameChain[0] = new Mat(IMG_HEIGHT + (IMG_HEIGHT / 2), IMG_WIDTH, CvType.CV_8UC1);
                mFrameChain[1] = new Mat(IMG_HEIGHT + (IMG_HEIGHT / 2), IMG_WIDTH, CvType.CV_8UC1);

                mCameraFrame = new JavaCameraFrame[2];
                mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], IMG_WIDTH, IMG_HEIGHT);
                mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], IMG_WIDTH, IMG_HEIGHT);

                switch (IMG_TYPE) {
                    case FMT_TYPE_YUV420: {
                        //                    IMG_LENGTH = IMG_WIDTH * IMG_HEIGHT * 3 / 2;
                        //                    IMG_DATA = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3 / 2);
                        //                    IMG_DATA_264 = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3);
                    }
                    break;
                    case FMT_TYPE_YUV422: {
                        //                    IMG_LENGTH = IMG_WIDTH * IMG_HEIGHT * 2;
                        //                    IMG_DATA = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 2);
                        //                    IMG_DATA_264 = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3);
                    }
                    break;
                    case FMT_TYPE_MJPEG: {
                        //                    IMG_LENGTH = IMG_WIDTH * IMG_HEIGHT * 3;
                        //                    IMG_DATA = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3);
                        //                    IMG_DATA_264 = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3);
                    }
                    break;
                    case FMT_TYPE_H264: {
                        //                    IMG_DATA_264 = ByteBuffer.allocateDirect(IMG_WIDTH * IMG_HEIGHT * 3);
                        IMG_LENGTH = IMG_WIDTH * IMG_HEIGHT * 3 / 2;
                        IMG_DATA = new byte[IMG_WIDTH * IMG_HEIGHT * 3 / 2];
                        IMG_DATA_COPY = new byte[IMG_WIDTH * IMG_HEIGHT * 3 / 2];
                        IMG_DATA_264 = new byte[IMG_WIDTH * IMG_HEIGHT * 3];
                        // 视频硬编码
                        mediaVideoCodec = MediaCodec.createEncoderByType("video/avc");
                        MediaFormat mediaVideoFormat = MediaFormat.createVideoFormat("video/avc", IMG_WIDTH, IMG_HEIGHT);
                        mediaVideoFormat.setInteger(MediaFormat.KEY_BIT_RATE, IMG_WIDTH * IMG_HEIGHT * 1);
                        mediaVideoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
                        mediaVideoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                                MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
                        mediaVideoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
                        mediaVideoCodec.configure(mediaVideoFormat, null, null,
                                MediaCodec.CONFIGURE_FLAG_ENCODE);
                        mediaVideoCodec.start();

                        IMG_SUB_DATA = new byte[IMG_SUB_WIDTH * IMG_SUB_HEIGHT * 3 / 2];
                        // 视频硬编码
                        sub_mediaVideoCodec = MediaCodec.createEncoderByType("video/avc");
                        MediaFormat sub_mediaVideoFormat = MediaFormat.createVideoFormat("video/avc", IMG_SUB_WIDTH, IMG_SUB_HEIGHT);
                        sub_mediaVideoFormat.setInteger(MediaFormat.KEY_BIT_RATE, IMG_SUB_WIDTH * IMG_SUB_HEIGHT * 1);
                        sub_mediaVideoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
                        sub_mediaVideoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                                MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
                        sub_mediaVideoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
                        sub_mediaVideoCodec.configure(sub_mediaVideoFormat, null, null,
                                MediaCodec.CONFIGURE_FLAG_ENCODE);
                        sub_mediaVideoCodec.start();
                    }
                    break;
                }

                textPaint.setTextSize(25);
                textPaint.setColor(Color.RED);

                //初始化 ffmpeg 解码
                Mp4v2Native.getInstance().jpeginit(CamID, IMG_WIDTH, IMG_HEIGHT);
            }
        } catch (Exception e) {
            cameraPosition = -1;
            LogUtils.i(TAG, "camera error:" + Log.getStackTraceString(e));
        }
    }

    //初始化相机
    private int initCameara() {
        /*try {
            cameraPosition = -1;
            Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
            for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
                Camera.getCameraInfo(i, cameraInfo);

                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT || cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    cameraPosition = i;
                    break;
                }
            }
            if (cameraPosition == -1)
                return cameraPosition;

        } catch (Exception e) {
            cameraPosition = -1;
            LogUtils.i(TAG, "camera error:" + Log.getStackTraceString(e));
        }*/

        mCarcorderManager = CarcorderManager.get();
        serviceFlag = mCarcorderManager.isServiceAlive();
        if(serviceFlag){
            mMainCameraDevice = mCarcorderManager.openCameraDevice(0);
            mMainCameraDevice.setVideoCallback(mVideoCallback);
            mMainCameraDevice.setAudioCallback(mAudioCallback);
            mCarcorderManager.addCarcorderDeathCallback(carcorderDeathCallback);
            cameraPosition= 0;

            //设置ACC 回调
            mCarcorderManager.addCarEngineChangedCallback(new CarcorderManager.CarEngineChangedCallback() {
                @Override
                public void onEngineChanged(int i) {
                    LogUtils.d(TAG,"ACC value:"+i);
                }
            });
        }
        return cameraPosition;
    }

    /**
     * 更新数据
     *
     * @param pdata 数据指针
     * @param size
     * @return
     */
    public int updateData(long pdata, int size) {
        int ret = 0;
        ret = Mp4v2Native.getInstance().mp4packVideo(CamID, pdata, size);
        return ret;
    }

    /**
     * 更新数据
     */
    public int updateRGBData(long pdata) {
        rgbdatap = pdata;
//        //人脸识别
//        if (CamService.FaceStatus == 1 && CamService.FaceTik >= 50) {
//            EasyFace.getInstance().nativeProcessFrame(rgbdatap, bmp.getHeight(), bmp.getWidth());
//        }
        return 0;
    }

    /**
     * 更新BGR数据
     */
    public int updateBGRData(int id, long pdata, int w, int h, int len) {
//        bgrdatap = pdata;
//        synchronized (bmpsyn) {
//            if (MyApplication.g_Previewstatus == 0){
//                //非预览状态下检测人脸数
//                EasyFace.getInstance().nativeGetFaceNumber(bgrdatap, w, h, len);
//            }
//        }
        return 0;
    }

    public int updateData2(byte[] data, int size) {
        int ret = 0;
        if (MP4FileHandle != 0) {
            ret = Mp4v2Native.getInstance().mp4packVideo2(CamID, data, size);
        }
        return ret;
    }

    public String getjpgfilename(int mediaID, int Cause, int hctd) {
        String lock_flag = CamService.lock_v == 1 ? "_lock" : "";
        lock_flag += CamService.flag_v == 1 ? "_flag" : "";
        lock_flag += Cause == 2 ? "_alarm" : "";
        String filenam = Utils.getCreatFileName(DEV_TYPE, false, lock_flag, mediaID, 1, Cause) + (hctd > 0 ? ("_" + hctd) : "") + ".jpg";
        return filenam;
    }

    public synchronized String  saveJpgFile(String tag, int mediaID, int Cause, int hctd) {
        String Causestr = "";

        String filenam = getjpgfilename(mediaID, Cause, hctd);
        File file = new File(filenam);
        try {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if(CamID == 0) {
                Mp4v2Native.getInstance().jpegsave(CamID, mediaID, filenam);
            }else{
                if(mMainCameraDevice !=null){
                    mMainCameraDevice.takePicture(filenam, null, new CameraDevice.PictureCallback() {
                        @Override
                        public void onPictureTaken(String s) {

                        }
                    });
                }
            }
            LogUtils.e(TAG, filenam);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return filenam;
    }

    public byte[] getDate() {
        return IMG_DATA;
    }

    public int getWidth() {
        return IMG_WIDTH;
    }

    public int getHeight() {
        return IMG_HEIGHT;
    }

    public int getFps() {
        return IMG_FPS;
    }

    public long createMp4File(String filename) {
        try {
            synchronized (videosyn) {
                if (DEV_TYPE == DEV_TYPE_USB) {
                    savetik = 1000 * 60 * 5;
                    filename += ".mp4";
                    savefilename = filename;
                    frameTik = 0;
                    frameCount = (int) (savetik / (1000 / FPS));
                    MP4FileHandle = Mp4v2Native.getInstance().mp4init(CamID, filename, IMG_WIDTH, IMG_HEIGHT, IMG_TIMESCALE, FPS/*IMG_FPS - 5*/, IMG_A_TIMESCALE, IMG_A_SAMPLE, 0);

                    saveStart = System.currentTimeMillis();
                    savefile = true;
                } else if (DEV_TYPE == DEV_TYPE_MIPI) {
                    savetik = 1000 * 60 * 5;
                    //filename += ".mp4";
                    //savefilename = filename;
                    savefilename = filename.substring(0,filename.indexOf("Front"))+"Front";
                    /*mCamera = Camera.open(cameraPosition);
                    mCamera.unlock();

                    //mCamera.setMipicallproc(CamID, Mp4v2Native.getInstance().getmipiproc());
                    //setMIPIBack(CamService.nMipiBackStatus);

                    //使用Android 视频存储
                    mRecorder = new MediaRecorder();
                    mRecorder.setCamera(mCamera);

                    // 这两项需要放在setOutputFormat之前
                    //mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
                    mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

                    // Set output file format
                    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

                    // 这两项需要放在setOutputFormat之后
                    // mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                    mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                    Log.d("lyj","mipi filename:"+filename);
                    mRecorder.setVideoSize(IMG_WIDTH, IMG_HEIGHT);
                    mRecorder.setVideoFrameRate(20);
                    mRecorder.setVideoEncodingBitRate(IMG_WIDTH * IMG_HEIGHT * 1);
                    mRecorder.setPreviewDisplay(MyApplication.mPrevewviewCam.getHolder().getSurface());
//                        mRecorder.setOrientationHint(90);
//                        //设置记录会话的最大持续时间（毫秒）
//                        mRecorder.setMaxDuration(30 * 1000);

                    mRecorder.setOutputFile(filename);
                    mRecorder.prepare();
                    Thread.sleep(200);
                    mRecorder.start();

                    LogUtils.i("jnimp4v2", "MIPI 创建文件MP4文件  " + filename);
                    saveStart = System.currentTimeMillis();*/
                    mMainCameraDevice.setPreviewSurface(MyApplication.mPrevewviewCam.getHolder().getSurface());

                    if (mMainCameraDevice.getState() == CameraDevice.STATE_IDLE){
                        mMainCameraDevice.startPreview();
                    }
                    if (mMainCameraDevice.getState() != CameraDevice.STATE_RECORDING){
                        startMipiRecord(mMainCameraDevice,savefilename);
                    }
                    savefile = true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return MP4FileHandle;
    }

    public void setMipiRecordState(boolean state){
        if(mMainCameraDevice != null){
            LogUtils.d("setMipiRecordState state:"+state);
            if(state){
                mMainCameraDevice.startRecord();
                StartTime = System.currentTimeMillis();
            }else{
                mMainCameraDevice.stopRecord();
            }
        }
    }

    public boolean startMipiRecord(CameraDevice mCameraDevice,String savefilename){
        int ret = -1;
        if(mCameraDevice != null){

            LogUtils.d(" start mipi record save file name is "+savefilename);

            CameraDevice.Parameters parameters = mCameraDevice.getParameters();
            parameters.setCameraId(0); //设置cameraid
            parameters.setOutputFile(savefilename); //设置视频保存位置
            //parameters.setYUVCallbackType(CameraDevice.YUVCallbackType.yuvCBAndRecord);
            //mCameraDevice.setYuvCallback(yuvCallback);

            parameters.setOutputFileFormat(CameraDevice.OutputFormat.MPEG_4);

            CamcorderProfile profile = CamcorderProfile.get(0,CamcorderProfile.QUALITY_720P);
            profile.videoFrameRate = 24;  //support 10,15,20,15,24,30
            parameters.setVideoProfile(profile); //video audio 编码器，帧率等设置
            parameters.setOutputFileName("MIPI");

            parameters.setSubVideoFrameMode(CameraDevice.VideoFrameMode.SOURCE);
            CamcorderProfile subprofile = CamcorderProfile.get(0,CamcorderProfile.QUALITY_720P);
            subprofile.videoFrameRate = 24;
            parameters.setSubVideoProfile(subprofile);
            parameters.enableSubVideoFrame(true);


            parameters.setVideoRotateDuration((int)savetik);
            parameters.enableVideoWatermarkText(true);
            parameters.enablePreviewWatermarkText(true);
            parameters.enablePictureWatermarkText(true);
            parameters.setWatermarkTextPosition(30, 80);
            parameters.setWatermarkArea(20, 20, 800, 100);
            parameters.setWatermarkText("");
            parameters.setWatermarkTextColor(Color.WHITE);
            parameters.setWatermarkTextSize(80);
            parameters.setWatermarkFontFile("/system/fonts/NotoSansCJK-Regular.ttc");

            //parameters.setVideoEncodingBitRate(1000000);
            parameters.setVideoBitRateRange(2 * 1000 * 1000, 3 * 1000 * 1000);
            parameters.setMainVideoFrameMode(CameraDevice.VideoFrameMode.DISABLE);
            mCameraDevice.setParameters(parameters);
            ret = mCameraDevice.startRecord();

            StartTime = System.currentTimeMillis();
            mCameraDevice.startSubVideoFrame();

            LogUtils.d("start mipi Record ret:"+ret);
        }
        return ret == 0;
    }

    private CarcorderManager.CarcorderDeathCallback carcorderDeathCallback = new CarcorderManager.CarcorderDeathCallback() {
        @Override
        public void onDeath(int i, String s) {
            LogUtils.d("service death i:"+i+ " s:"+s);
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    };

    /*视频流数据回调*/
    private CameraDevice.VideoCallback mVideoCallback = new CameraDevice.VideoCallback() {
        @Override
        public void onVideoTaken(int eventType, int cameraId, String vedioname) {
            //LogUtils.d("lyj video callback onVideoTaken eventType: "+eventType+" cameraId:"+cameraId+" vedioname:"+vedioname );
            if(eventType == VIDEO_EVENT_ADD_FILE_IN_GALLERY){
                Bundle mainBundle = new Bundle();
                mainBundle.putInt("ChannclID", 2);

                try{
                    int LSH = mainBundle.getInt("LSH", -1);
                    int MediaID  = MyApplication.GetMediaID();
                    mainBundle.putInt("MediaID", MediaID);
                    mainBundle.putInt("MediaType", 2);
                    mainBundle.putInt("MediaCode", 4);
                    mainBundle.putInt("EventCode", 1);
                    mainBundle.putInt("PTType", 1);
                    mainBundle.putInt("Cause", 0);
                    mainBundle.putString("FilePath", vedioname);
                    mainBundle.putLong("StartTime", StartTime);
                    File file = new File(vedioname);
                    if (file.exists()) {
                        mainBundle.putInt("FileLength", (int) file.length());
                    }
                    if (LSH != -1) {
                        ArrayList<Integer> mMedias = new ArrayList<Integer>();
                        mMedias.add(MediaID);
                        mainBundle.putIntegerArrayList("mMedias", mMedias);
                        mainBundle.putInt("EventCode", 0);
                        mainBundle.putInt("Cause", 3);
                        mainBundle.putInt("Result", 0);
                        LogUtils.d("时间段停止 LSH = " + LSH);
                        MyApplication.mDvrManager.mDvrCallBack.doVedio(mainBundle);
                        mainBundle.putInt("LSH", -1);
                    }
                    // 保存多媒体信息在数据库
                    if (MyApplication.mDvrManager.mDvrCallBack != null) {
                        LogUtils.d("onVideoTaken AddMediaEx mainBundle"+mainBundle );
                        MyApplication.mDvrManager.mDvrCallBack.AddMediaEx(mainBundle);
                        StartTime = System.currentTimeMillis();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onVideoFrame(byte[] data, int dataType, int size) {
            int mDataType = 0;
            if(mSpsData == null ){
                mDataType = checkFrameType(data);
                if(mDataType == 1){
                    mSpsData = new byte[size];
                    System.arraycopy(data,0,mSpsData,0,size);
                }
            }

            if(sendMipiData)
            {
                if(mSpsData != null ){
                    mDataType = checkFrameType(data);
                    byte[] mEncodeData = null;
                    if(mDataType == 3){
                        mEncodeData = new byte[mSpsData.length +size];
                        System.arraycopy(mSpsData,0,mEncodeData,0,mSpsData.length);
                        System.arraycopy(data,0,mEncodeData,mSpsData.length,size);
                        Mp4v2Native.getInstance().mipiSendH264Data(CamID, mEncodeData, mEncodeData.length, 1, 0);
                    }
                    else{
                        Mp4v2Native.getInstance().mipiSendH264Data(CamID, data, size, 1, 0);
                    }
                }
            }
        }
    };

    public static int checkFrameType(byte[] data) {
        if( data == null || data.length < 5) {
            return -1;
        }
        //data[4]为NALU类型
        if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0 && data[3] == 0x1 && data[4] == 0x67) { //sps
            return 1;
        }else if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0 && data[3] == 0x1 && data[4] == 0x68) { //pps
            return 2;
        }

        byte nalu = data[4];
        if((nalu & 0x1F) == 5){
            return 3; //I
        }
        return -1;
    }

    /*音频流回调*/
    private CameraDevice.AudioCallback mAudioCallback = new CameraDevice.AudioCallback() {
        @Override
        public void onAudioFrame(byte[] bytes, int i, int i1) {

        }
    };

    public void setMIPIBack(int status) {
        // 1 音频 2 视频 3 音视频
        //mCamera.setMPEG4Back(status);
    }

    public int updateAudioData(long pdata, int size) {
        int ret = 0;
        if (MP4FileHandle != 0) {
            ret = Mp4v2Native.getInstance().mp4packAudio(CamID, pdata, size);
        }
        return ret;
    }

    public int updateAudioData2(byte[] data, int size) {
        int ret = 0;
        if (MP4FileHandle != 0) {
            ret = Mp4v2Native.getInstance().mp4packAudio2(CamID, data, size);
        }
        return ret;
    }

    public int closeMp4File() {
        int ret = 0;
        synchronized (videosyn) {
            if (MP4FileHandle != 0) {
                //关闭usb摄像头写文件
                ret = Mp4v2Native.getInstance().mp4close(CamID);
            }

            /*if (DEV_TYPE == DEV_TYPE_MIPI) {
                try {
                    //关闭MIPI 摄像头
                    mRecorder.stop();
                    mRecorder.release();

                    mCamera.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }*/
            savefile = false;
            savetik = 1000 * 60 * 5;
        }
        return ret;
    }

    public int initRTP(String IP, int Port, int UdpPort, int DataType, int StreamType, byte[] Cmd1209, int PTTYPE,int is1078) {
        //rtp服务器IP
        rtp_IP = IP;
        //rtp服务器端口
        rtp_Port = Port;
        rtp_UdpPort = UdpPort;
        //监控数据类型
        rtp_DataType = DataType;
        //码流类型
        rtp_StreamType = StreamType;
        if (CamID == 0) usbDataisUploading = true;
        return Mp4v2Native.getInstance().RTPstart(CamID, rtp_IP, rtp_Port, rtp_UdpPort, rtp_DataType, rtp_StreamType, 0, PTTYPE, is1078==1?950:1400, Cmd1209, is1078);
    }

    public int ctrlRTP(int KZZL, int YSPLX, int MLLX) {
        if (CamID == 0) usbDataisUploading = false;
        return Mp4v2Native.getInstance().RTPctrl(CamID, KZZL, YSPLX, MLLX);
    }

    public int initfileRTP(String IP, int Port, int UdpPort, int DataType, int KJKT, int StreamType, String filename, byte[] Cmd1209, int PTTYPE,int is1078) {
        //rtp服务器IP
        rtp_IP = IP;
        //rtp服务器端口
        rtp_Port = Port;
        rtp_UdpPort = UdpPort;
        //监控数据类型
        rtp_DataType = DataType;
        //快进快退标识
        rtp_KJKT = KJKT;
        //码流类型
        rtp_StreamType = StreamType;
        if (CamID == 0) usbDataisUploading = true;
        setVideoParams();
        Mp4v2Native.getInstance().RTPfilestart(CamID, rtp_IP, rtp_Port, rtp_UdpPort, rtp_DataType, rtp_KJKT, rtp_StreamType, 0, PTTYPE, is1078 == 1 ? 950 : 1402, filename, Cmd1209,is1078);
        return 1;
    }

    public int ctrlfileRTP(int CSKZ, int KJKT_BS, String TDHFWZ) {
        if (CamID == 0) usbDataisUploading = false;
        return Mp4v2Native.getInstance().RTPfilectrl(CamID, CSKZ, KJKT_BS, TDHFWZ);
    }

    private int num = 0;
    boolean[] rtpstatus = new boolean[1];
    private int cameraID = 0;

    public long waterTime = 0;
    public int videoread() {
        int ret = -1;
        synchronized (videosyn) {

            if (IMG_DATA != null &&   IMG_SUB_DATA != null) {
                ret = Mp4v2Native.getInstance().videoread(CamID, bmp, IMG_DATA, IMG_SUB_DATA, rtpstatus);
            }


//            LogUtils.d("videoread =========" + num++);

            synchronized (bmpsyn){
                if (MyApplication.g_Previewstatus == 1){
                    mFrameChain[0].put(0, 0, IMG_DATA);
                    org.opencv.android.Utils.matToBitmap(mCameraFrame[0].rgba(), bmp);
                }
            }

            synchronized (facesyn){
                mFrameChain[1].put(0, 0, IMG_DATA);
            }

            // 已经录制了多长时间
            long time = System.currentTimeMillis() - saveStart;

            int encodeNumber = (int) ((time / (1000 / FPS)) - frameTik);
//            do {
//                LogUtils.e("帧总数 = " + frameCount + "    当前帧数 = " + frameTik + "  需要插入帧数  encodeNumber = " + encodeNumber + "   已录制时长 = " + time);
                if (IMG_DATA != null && mediaVideoCodec != null) {
                    setVideoParams();
                    int len = Encode264(mediaVideoCodec, IMG_DATA, IMG_DATA_264);
                    if (len > 0){
                        Mp4v2Native.getInstance().mp4packVideo2(CamID, IMG_DATA_264, len);
                    }
                }
                encodeNumber--;
                //编码帧计数
                frameTik++;
//            }while (encodeNumber > 0);

            if (rtpstatus[0] && IMG_SUB_DATA != null && sub_mediaVideoCodec != null) {
                int len = Encode264_sub(sub_mediaVideoCodec, IMG_SUB_DATA, IMG_DATA_264);
                if (len>0){
                    Mp4v2Native.getInstance().mp4packVideo2sub(CamID, IMG_DATA_264, len);
                }
            }
        }

        if (IsWatermarkexDate){
            if(System.currentTimeMillis() - waterTime >= 1000){
                waterTime = System.currentTimeMillis();
                SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
                String suffix = fmt.format(waterTime);
                setWatermarkex(0, suffix, 10, 10, 1);
            }
        }


        return ret;
    }

    private static String hexStr = "0123456789ABCDEF"; //全局
    public static String BinaryToHexString(byte bytes) {
        String result = "";
        String hex = "";

        //字节高4位
        hex = String.valueOf(hexStr.charAt((bytes & 0xF0) >> 4));
        //字节低4位
        hex += String.valueOf(hexStr.charAt(bytes & 0x0F));
        result += hex;

        return result;
    }

    public int videowatermark(int group, String info) {
        int ret;
        synchronized (videosyn) {
            ret = Mp4v2Native.getInstance().videowatermark(CamID, group, info);
        }
        return ret;
    }

    @SuppressLint("NewApi")
    public int Encode264(MediaCodec mediaCodec, byte[] yuv420, byte[] output) {
        int pos = 0;
        try {
//            ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
//            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
            int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0) {
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
//                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();
                inputBuffer.put(yuv420);
                mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 0, 0);
            }
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
            do {
                if (outputBufferIndex >= 0) {
//                    ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);

                    byte[] outData = new byte[bufferInfo.size];
                    outputBuffer.get(outData);
                    if (m_info != null) {
                        System.arraycopy(outData, 0, output, pos, outData.length);
                        pos += outData.length;
                    } else // 保存pps sps 只有开始时 第一个帧里有， 保存起来后面用
                    {
                        ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);
                        if (spsPpsBuffer.getInt() == 0x00000001) {
                            m_info = new byte[outData.length];
                            System.arraycopy(outData, 0, m_info, 0, outData.length);
                        } else {
                            return -1;
                        }
                    }
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);

                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
//                    outputBuffers = mediaCodec.getOutputBuffers();
                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    MediaFormat format = mediaCodec.getOutputFormat();
                    format = null;
                }
            } while (outputBufferIndex >= 0);
            if (output[4] == 0x65 || output[4] == 0x25) // key frame 编码器生成关键帧时只有
            // 00 00 00 01 65 没有pps
            // sps， 要加上
            {
                System.arraycopy(output, 0, yuv420, 0, pos);
                System.arraycopy(m_info, 0, output, 0, m_info.length);
                System.arraycopy(yuv420, 0, output, m_info.length, pos);
                pos += m_info.length;
            }

        } catch (Exception t) {
            t.printStackTrace();
        }
        return pos;
    }

    @SuppressLint("NewApi")
    public int Encode264_sub(MediaCodec mediaCodec, byte[] yuv420, byte[] output) {
        int pos = 0;
        try {
//            ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
//            ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
            int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0) {
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
//                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();
                inputBuffer.put(yuv420);
                mediaCodec.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 0, 0);
            }
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
            do {
                if (outputBufferIndex >= 0) {
//                    ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);

                    byte[] outData = new byte[bufferInfo.size];
                    outputBuffer.get(outData);
                    if (m_sub_info != null) {
                        System.arraycopy(outData, 0, output, pos, outData.length);
                        pos += outData.length;
                    } else // 保存pps sps 只有开始时 第一个帧里有， 保存起来后面用
                    {
                        ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);
                        if (spsPpsBuffer.getInt() == 0x00000001) {
                            m_sub_info = new byte[outData.length];
                            System.arraycopy(outData, 0, m_sub_info, 0, outData.length);
                        } else {
                            return -1;
                        }
                    }
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);

                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
//                    outputBuffers = mediaCodec.getOutputBuffers();
                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    MediaFormat format = mediaCodec.getOutputFormat();
                    format = null;
                }
            } while (outputBufferIndex >= 0);
            if (output[4] == 0x65 || output[4] == 0x25) // key frame 编码器生成关键帧时只有
            // 00 00 00 01 65 没有pps
            // sps， 要加上
            {
                System.arraycopy(output, 0, yuv420, 0, pos);
                System.arraycopy(m_sub_info, 0, output, 0, m_sub_info.length);
                System.arraycopy(yuv420, 0, output, m_sub_info.length, pos);
                pos += m_sub_info.length;
            }

        } catch (Exception t) {
            t.printStackTrace();
        }
        return pos;
    }

    public int setWatermarkex(int index, String params, int x, int y, int s) {
        int ret = Mp4v2Native.getInstance().videowatermarkex(CamID, index, params, x, y, s);
        return ret;
    }

    private int mPreviewFormat = ImageFormat.YV12;

    public class JavaCameraFrame implements CvUSBPreview.CvCameraViewFrame {
        public Mat gray() {
            return mYuvFrameData.submat(0, mHeight, 0, mWidth);
        }

        public Mat rgba() {
            if (mPreviewFormat == ImageFormat.NV21)
                Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_NV21, 3);//COLOR_YUV2RGBA_NV21
            else if (mPreviewFormat == ImageFormat.YV12)
                Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 3);  // COLOR_YUV2RGBA_YV12 produces inverted colors
            else
                throw new IllegalArgumentException("Preview Format can be NV21 or YV12");

            return mRgba;
        }

        public JavaCameraFrame(Mat Yuv420sp, int width, int height) {
            super();
            mWidth = width;
            mHeight = height;
            mYuvFrameData = Yuv420sp;
            mRgba = new Mat();
        }

        public void release() {
            mRgba.release();
        }

        private Mat mYuvFrameData;
        private Mat mRgba;
        private int mWidth;
        private int mHeight;
    }

    private void setVideoParams(){
        String simNo = Utils.simNo;
        byte[] sims = Utils.StrToBCDBytes(simNo);
        int channelNumber = cameraID == 4 ? 2 : 1;   //cameraID 为4表示前置摄像头，监控车辆正前方；cameraID 为0表示USB摄像头，监控驾驶员
        if (sims.length>5){
            Mp4v2Native.getInstance().setParams(cameraID, channelNumber, Integer.parseInt(BinaryToHexString(sims[0]),16), Integer.parseInt(BinaryToHexString(sims[1]),16),
                    Integer.parseInt(BinaryToHexString(sims[2]),16), Integer.parseInt(BinaryToHexString(sims[3]),16), Integer.parseInt(BinaryToHexString(sims[4]),16),
                    Integer.parseInt(BinaryToHexString(sims[5]),16));
        }
    }
}
